package server;

import connect.ConnectionData;

import java.util.*;

public class BroadcastCommandParser implements CommandParser {
    private final String NICK = "nick";
    private final String USERS = "users";
    private final String EXIT = "exit";
    private final String VERSION = "version";
    private final String VERIFY = "verify";
    private final String REGISTER = "register";
    private final String WHO_AM_I = "whoami";
    private final String MSG = "msg";
    private final String STATS = "stats";
    private final String FILE = "file";
    private final String ONLINE = "online";
    private final String FRIEND = "friend";
    private final String ACFRIEND = "acfriend";
    private final String tab = "&nbsp;&nbsp;&nbsp;";
    private DataSource ds;
    private final int sek = 1000;
    private final int min = 60 * sek;
    private final int hours = 60 * min;
    private final int days = 24 * hours;

    public static final char COMMAND = 0xFD;

    public BroadcastCommandParser() {
        System.out.println("BroadcastCommandParser");
    }

    public void runCommand(ConnectedClient cc, ConnectionData con) {
        try {
            if (ds == null) {
                System.out.println("CommandParser: DataSoruce Missing");
                cc.sendMessage("Server: Your command didn't get parsed, The Server Admin knows why ;)");
            } else {
                String str = con.getToken();
                StringTokenizer strTok = new StringTokenizer(str);
                String command = strTok.nextToken();
                if (command.equalsIgnoreCase(NICK))
                    if (strTok.hasMoreTokens()) setNick(cc, strTok.nextToken());
                    else cc.sendMessage("usage: /nick <newNick>");
                else if (command.equalsIgnoreCase(USERS))
                    users(cc);
                else if (command.equalsIgnoreCase(EXIT))
                    exit(cc);
                else if (command.equalsIgnoreCase(VERIFY))
                    verifyNick(cc, strTok.nextToken());
                else if (command.equalsIgnoreCase(REGISTER))
                    registerNick(cc, strTok.nextToken(), strTok.nextToken());
                else if (command.equalsIgnoreCase(WHO_AM_I))
                    whoAmI(cc);
                else if (command.equalsIgnoreCase(MSG)) {
                    msg(cc, strTok.nextToken(), strTok, con);
                } else if (command.equalsIgnoreCase(FILE)) {
                    file(cc, strTok.nextToken(), con);
                } else if (command.equalsIgnoreCase(ONLINE)) {
                    online(cc);
                } else if (command.equalsIgnoreCase(FRIEND)) {
                    friend(cc, strTok.nextToken());
                } else if (command.equalsIgnoreCase(ACFRIEND)) {
                    acfriend(cc, strTok);
                } else if (command.equalsIgnoreCase(STATS))
                    stats(cc);
            }
        } catch (Exception e) {
            System.out.println("CommandParser: " + e.getMessage());
            cc.sendMessage("Invalid Command: " + con.getToken());
        }
    }

    private void acfriend(ConnectedClient cc, StringTokenizer strTok) {
        String user=strTok.nextToken();
        String str=strTok.nextToken();
        ConnectionData con = new ConnectionData("acfriend " + cc.nick +" "+ str);
        con.setFunction();
        cc.sendTo(user, con);
    }

    private void friend(ConnectedClient cc, String user) {
        ConnectionData con = new ConnectionData("friend " + cc.nick);
        con.setFunction();
        cc.sendTo(user, con);
    }

    private void online(ConnectedClient cc) {
        String msghead = "online " + cc.nick;
        ConnectionData toSend = new ConnectionData(msghead);
        toSend.setFunction();
        cc.broadcastMessage(toSend);
    }

    private void file(ConnectedClient cc, String user, ConnectionData con) {
        String msghead = "file " + cc.nick + " (private send to you a file)";
        ConnectionData toSend = new ConnectionData(msghead);
        toSend.setFunction();
        cc.sendTo(user, toSend);
    }

    private void stats(ConnectedClient cc) {
        long runningTime = System.currentTimeMillis() - MainServer.uptime;
        String str = "Server has been running for " + printTime(runningTime) + "<br>" +
                "User connects since uptime " + MainServer.connects + "<br>";


        cc.sendMessage(str);
    }

    private String printTime(long time) {
        String str = "";
        if (time < sek) {
            str += "" + time + "ms";
            return str;
        }
        if (time > sek && time < min) {
            long t = time % sek;
            str += "" + (time / sek) + "sek " + printTime(t);
            return str;
        }
        if (time > min && time < hours) {
            long t = time % min;
            str += "" + (time / min) + "min " + printTime(t);
            return str;
        }
        if (time > hours && time < days) {
            long t = time % hours;
            str += "" + (time / hours) + "hours " + printTime(t);
        }
        return str;
    }

    private void msg(ConnectedClient cc, String user, StringTokenizer strTok, ConnectionData con) {
        if (con.isImage()) {
            ConnectionData toSend = new ConnectionData(con.getPicture());
            toSend.setToken("msg " + cc.nick + " (private send to you):");
            toSend.setFunction();
            cc.sendTo(user, toSend);
        } else {
            StringBuffer strBuff = new StringBuffer();
            while (strTok.hasMoreTokens())
                strBuff.append(strTok.nextToken() + " ");
            String msghead = "msg " + cc.nick + " (private send to you):" + strBuff.toString();
            ConnectionData toSend = new ConnectionData(msghead);
            toSend.setFunction();
            cc.sendTo(user, toSend);
        }
    }

    private void users(ConnectedClient cc) {
        LinkedList users = (LinkedList) ((cc.getConnectionKeeper().users()).clone());
        String msg = "users ";
        boolean First = true;
        while (users.size() > 0) {
            if (First) {
                First = false;
            } else {
                msg += ",";
            }
            msg += ((ConnectedClient) (users.removeFirst())).getNick();
        }
        ConnectionData toSend = new ConnectionData(msg);
        toSend.setFunction();
        cc.broadcastMessage(toSend);
    }

    private void setNick(ConnectedClient cc, String str) {
        //System.out.println("" + cc.nick + " is now known as " + str);
        /*cc.nick = str;
        cc.sendMessage("Server: Your are now known as " + str);*/
        cc.verifyedBoolean = false;
        boolean verify = ds.verifyUser(str, "");
        if (verify) {
            if (isNickFree(cc, str)) {
                cc.nick = str;
                cc.verifyedBoolean = true;
            } else
                cc.sendMessage("nick " + str + " was allready taken");


        } else {
            cc.verifyedCount = 5;
            cc.tmpNick = str;
            cc.sendMessage("Nick " + str + " is registered so you have to " +
                    "verify that this nick is yours");
        }
    }

    private boolean isNickFree(ConnectedClient cc, String nick) {
        LinkedList users = (LinkedList) ((cc.getConnectionKeeper().users()).clone());
        Iterator it = users.iterator();
        while (it.hasNext()) {
            ConnectedClient comp = ((ConnectedClient) (it.next()));
            String compNick = comp.getNick();
            if (nick.equalsIgnoreCase(compNick)) return false;
        }
        return true;
    }

    private void whoAmI(ConnectedClient cc) {
        cc.whoAmI();
    }

    private void registerNick(ConnectedClient cc, String nick, String pass) {
        if (pass.length() < 4 || nick.length() < 4) {
            cc.sendMessage("Your nick/password needs to be atleast 4 chars long");
        } else {
            if (ds.addUser(nick, pass)) {
                cc.sendMessage("User " + nick + " is now registered and set as your own");
                cc.nick = nick;
                cc.verifyedBoolean = true;
            } else {
                cc.sendMessage("The username is allready taken");
            }

        }
    }

    private void verifyNick(ConnectedClient cc, String password) {
        if (ds.verifyUser(cc.tmpNick, password)) {
            cc.nick = cc.tmpNick;
            cc.verifyedBoolean = true;
        } else {
            cc.nick = "" + cc.portNumber;
            cc.sendMessage("Invalid user/pass, your nick is set to " + cc.nick);
        }
    }

    private void exit(ConnectedClient cc) {
        cc.sendMessage("Server: You are being disconected!");
        try {
            Thread.sleep(50);
        } catch (Exception e) {
        }
        cc.dropClient();
    }

    public void setDataSource(DataSource ds) {
        this.ds = ds;
    }
}
